package dq.study.minimvc.reflect;

import dq.study.minimvc.paramter.MethodArgumentResolver;
import dq.study.minimvc.paramter.MultiArgumentResolver;
import dq.study.minimvc.paramter.SimpleArguementResolver;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class InvocableHandlerMethod extends HandlerMethod {
    private static final Object[] EMPTY_ARGS = new Object[0];
    private List<MethodArgumentResolver> argumentResolvers = new LinkedList<>();


    public InvocableHandlerMethod(Object bean, Method method) {
        super(bean, method);
        initResolvers();
    }

    public InvocableHandlerMethod(HandlerMethod handlerMethod) {
        super(handlerMethod);
        initResolvers();
    }

    private void initResolvers(){
        argumentResolvers.add(new MultiArgumentResolver());
        argumentResolvers.add(new SimpleArguementResolver());
    }


    protected Object doInvoke(Object... args) throws Exception {
        return getMethod().invoke(getBean(),args);
    }


    public Object invokeForRequest(HttpServletRequest request) throws Exception {
        Object[] args = getMethodArgumentValues(request);
        return doInvoke(args);
    }

    private Object[] getMethodArgumentValues(HttpServletRequest request) throws Exception {
        Parameter[] parameters = getMethodParameters();
        MethodArgumentResolver resolver = null;
        if (parameters.length==0) {
            return EMPTY_ARGS;
        }
        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            for (MethodArgumentResolver methodArgumentResolver : argumentResolvers){
                if (methodArgumentResolver.supportsParameter(parameters[i])){
                    resolver = methodArgumentResolver;
                    break;
                }
            }
            args[i] = resolver.resolveArgument(parameters[i],request);
        }
        return args;
    }
}
